//
//  VCDownloadTs.m
//  VC
//
//  Created by 肖康龙 on 2017/8/30.
//  Copyright © 2017年 vsoontech. All rights reserved.
//

#import <AVKit/AVKit.h>

#import "VCDownloadTs.h"
#import "GCDAsyncUdpSocket.h"
#import "DataUdp.pbobjc.h"
#import "TunnelUdp.pbobjc.h"
#import "VCTsDataModel.h"
#import "VCDowmload.h"


@interface VCDownloadTs ()<GCDAsyncUdpSocketDelegate>

/**socket*/
@property (strong, nonatomic)GCDAsyncUdpSocket * udpSocket;
/**下载的*/
@property (strong, nonatomic)GCDAsyncUdpSocket * udpSocketDownload;

/**下载的数据*/
@property (nonatomic,strong)VCTsDataModel *dataModel;

/**接受到多少个*/
//@property (nonatomic,assign)NSUInteger appendNum;
/**全部接受包的bitMap*/
@property (nonatomic,strong)NSMutableData *acceptBitmap;

/**一共要下载多少个包*/
@property (nonatomic,assign)int totalPackNum;

/**用来记录当前的ts*/
@property (nonatomic,assign)int subId;

/**通道信息*/
@property (nonatomic,strong)ResponseTunnel *responseTunnel;
/**这一秒的速率*/
@property (nonatomic,assign)NSUInteger currentRate;
/**当前状态0打通道 1订阅 2在下载*/
@property (nonatomic,assign)int downloadState;
/**总共的下载量*/
@property (nonatomic,assign)NSUInteger downloadTotal;
/**最后接受到的包的时间戳*/
@property (nonatomic,assign)NSTimeInterval LastTimestamp;

/**标识接收情况的位图, 第N包已经收到, 则第 (N-Start)位置为1,反之为0*/
@property (nonatomic,strong)NSMutableData *Bitmap;
/**用来校验,假如出现下载ts中途断了,通过判断bitmap是不是一直不变,来判断是否断了,重新订阅*/
@property (nonatomic,strong)NSData *Bitmap_check;
/**用来记录正在下载的ts有多少秒没有下载包下来*/
@property (nonatomic,assign)int seconds;
/**用来记录当前下载最大的包序号是多少,用来判断是否需要辅助下载,还有300个包以上没有下载的才要辅助,*/
@property (nonatomic,assign)int pageMaxIndex;

/**请求超时的统计*/
/**打通道请求超时的次数*/
@property (nonatomic,assign)int tunnelFailNum;
/**订阅请求超时的次数*/
@property (nonatomic,assign)int subcribeFailNum;
/**是否从新请求了通道*/
@property (nonatomic,assign)BOOL isNewTunnel;
/**是否超时通道*/
@property (nonatomic,assign)BOOL isOutTimeTunnel;
/**是否超时订阅*/
@property (nonatomic,assign)BOOL isOutTimeSubcribe;
/**是否有一个订阅的延时方法*/
@property (nonatomic,assign)BOOL isDelaySubcribe;

@end



@implementation VCDownloadTs

-(void)dealloc{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [NSObject cancelPreviousPerformRequestsWithTarget:self];
    [self.udpSocket close];
    [self.udpSocketDownload close];
    self.udpSocket = nil;
    self.udpSocketDownload = nil;
}
- (instancetype)init
{
    self = [super init];
    if (self) {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reportSituation) name:VCDownloadReportNotification object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(debugSituation) name:VCDownloadDebugNotification object:nil];
        self.isFree = YES;
    }
    return self;
}
/**关闭下载器*/
-(void)closeDownload{
    [self.udpSocket close];
    [self.udpSocketDownload close];
    self.udpSocket = nil;
    self.udpSocketDownload = nil;
}
/**停止下载当前的ts*/
-(void)stopDownloadTs{
    self.isFree = YES;
    
    self.subId++;
    if (self.subId > 10000) {
        self.subId = 1;
    }
    self.dataModel = nil;//重新来一个存储数据
    self.currentTsNum = 0;
    self.seconds = 0;
    self.acceptBitmap = nil;
    self.dict_file = nil;
    [self setBitmapAndAcceptBitmap];
    self.subcribeFailNum = 0;//重新计算超时
    self.tunnelFailNum = 0; //打通道重新计算
    
    [self closeDownload];
}
/**查看当前ts下载进度 百分比,100为下载完毕*/
-(int)getTsDownloadProgress{
    
    CGFloat downloadTS = 0;
    Byte *byte = (Byte *)[self.Bitmap bytes];
    
    for (int i = 0;i < self.Bitmap.length; i++) {
        for (int j = 0; j < 8; j++) {
            char num = byte[i]>>j & 0x01;
            downloadTS += num * 1400;
        }
        
    }
    int percentage = (int)(downloadTS/(self.Bitmap.length*1400*8)*100);
    return percentage;
}
-(VCTsDataModel *)dataModel{
    if (_dataModel == nil) {
        _dataModel = [[VCTsDataModel alloc] init];
    }
    return _dataModel;
}

/**debug*/
-(void)debugSituation{
    if ([self.delegate respondsToSelector:@selector(download:bitMap:)]) {
        [self.delegate download:self
                         bitMap:self.Bitmap];
    }
}

/**上报当前情况*/
-(void)reportSituation{
    
    if (self.udpSocketDownload) {
        if ([self.delegate respondsToSelector:@selector(download:instantaneousSpeed:downloadTotal:tunnelId:state:)]) {
            [self.delegate download:self
                 instantaneousSpeed:self.currentRate
                      downloadTotal:self.downloadTotal
                           tunnelId:self.responseTunnel.tunnelId
                              state:self.downloadState];
        }
        Request_Report *report = [[Request_Report alloc] init];
        report.tunnelId = self.responseTunnel.tunnelId;
        report.subId = self.subId;
        report.lastRecvRate = self.currentRate;//最近一秒的瞬时速率
        report.lastTimestamp = self.LastTimestamp;//最新的收到的数据包的Timestamp,用于服务端计算RTT
        report.bitmap = self.Bitmap;//该订阅总共已接收到多少包,需要严格于下面的Bitmap匹配
        
        Request *req = [[Request alloc] init];
        req.type = Request_Type_Report;
        req.report = report;

        if (!self.isFree && [self.Bitmap isEqual:self.Bitmap_check]) {//正在下载,并且下载包没有变
            if (self.seconds<10) {
                self.seconds++;
            }else{//超过十秒没有数据来 重新下载
                
                [self startSubcribeWithIsCreateData:NO];//重新
                NSLog(@"%@第一个ts数据保存 来了这里了________就是重新下载这里 比例 = %i",self,[self getTsDownloadProgress]);
                self.seconds = 0;
            }
            
        }else{
            if (!self.isFree) {//在下载的时候才更新数据
                self.Bitmap_check = [NSData dataWithData:self.Bitmap];//更新数据
            }
        }
        
        
        if (!self.isFree){
            [self.udpSocketDownload sendData:[req data] toHost:self.host port:self.responseTunnel.tunnelPort withTimeout:SOCKET_OUT_TIME tag:0];
        }
        
    }
    self.currentRate = 0;//每次接受到通知就重新计算
    
}

/**开始下载*/
-(void)startDownload{
    self.isFree = NO;
    self.tSize = 0;
    self.timer = [[NSDate date] timeIntervalSince1970];
    if (self.udpSocketDownload) {//重新来
        self.subId++;
        if (self.subId > 10000) {
            self.subId = 1;
        }
        self.dataModel = nil;//重新来一个存储数据
        self.seconds = 0;
//        self.appendNum = 0;
        self.acceptBitmap = nil;
        [self setBitmapAndAcceptBitmap];
        self.subcribeFailNum = 0;//重新计算超时
        [self startSubcribeWithIsCreateData:YES];
    }else{
        /**打通道*/
        [self openTunnel];
    }
    
}

/**开始下载 辅助下载*/
-(void)auxiliaryStartDownload{
    self.isFree = NO;
    self.tSize = 0;
    self.timer = [[NSDate date] timeIntervalSince1970];
    if (self.udpSocketDownload) {//重新来
        self.subId++;
        self.dataModel = nil;//重新来一个存储数据
        self.seconds = 0;
//        self.appendNum = 0;
        self.acceptBitmap = nil;
        [self setBitmapAndAcceptBitmap];
        self.subcribeFailNum = 0;//重新计算超时
        [self startSubcribeWithIsCreateData:YES];
    }else{
        /**打通道*/
        [self openTunnel];
    }
}
/**是否需要辅助下载*/
-(BOOL)isNeedAuxiliary{
    if (self.totalPackNum + self.startPoint - self.pageMaxIndex > 300) {
        return YES;
    }
    return NO;
}
/**放回需要辅助的开始点*/
-(NSUInteger)auxiliaryStartPoint{
    
    int remaining = (int)(self.totalPackNum + self.startPoint - self.pageMaxIndex);//剩余量
    
    //给三分之二给辅助来下载
    NSUInteger startPoint = (NSUInteger)self.pageMaxIndex + remaining * 0.2;

    [self createAcceptBitmapWith:(int)(startPoint-1 - self.startPoint)];//调整完成标记
    /**调整下载范围*/
    [self changeBitmapWithAcceptIndex:(int)(startPoint-1 - self.startPoint)];
    self.totalPackNum = (int)(startPoint-1 - self.startPoint);
    self.endPoint = self.totalPackNum + self.startPoint;
    [self startSubcribeWithIsCreateData:NO];//重新
    
    return startPoint;
}

/**先获取end 在获取start 否则结束时间不正确,放回需要辅助的结束点*/
-(NSUInteger)auxiliaryEndPoint{
    return self.totalPackNum+self.startPoint;
}

/**将不需要自己下载的设置为1
 *endIndex : 结束位置
 */
-(void)changeBitmapWithAcceptIndex:(int)AcceptIndex{
    
//    int max = self.totalPackNum/8;
//    max++;
    
    int loca = AcceptIndex/8;
    self.Bitmap = [[self.Bitmap subdataWithRange:NSMakeRange(0, loca+1)] mutableCopy];
    
//    int length = max - loca;
    
//    NSRange range = NSMakeRange(loca, length);
    
//    Byte byte[length];
//    for (int i = 0; i<length; i++) {
//        if (i == 0) {
//            byte[i]= 0xff << AcceptIndex%8;
//        }else{
//            byte[i]= 0 | 0xff;
//        }
//    }

//    [self.Bitmap replaceBytesInRange:range withBytes:byte];//重新替换
    
    
}

/**设置bitmap和AcceptBitmap*/
-(void)setBitmapAndAcceptBitmap{
    if (self.isAuxiliaryDownload) {
        self.totalPackNum = (int)(self.endPoint - self.startPoint);
    }else{
        unsigned int size = [[self.dict_file objectForKey:@"fileSize"] unsignedIntValue];
        self.totalPackNum = size / PAGE_SIZE;
        if (size % PAGE_SIZE == 0) {
            self.totalPackNum--;
        }
    }
    [self createBitmapWith:self.totalPackNum];/**初始化bitmap*/
    [self createAcceptBitmapWith:self.totalPackNum];//添加完成标记
}

/**打通道*/
-(void)openTunnel{
    if (self.isFree) return;//当前不需要下载了
    
    [self setBitmapAndAcceptBitmap];
    
    self.downloadState = 0;//下载状态
    /**打通道*/
    RequestTunnel *res = [[RequestTunnel alloc] init];
    res.version = 1;
    res.clientId =[[[UIDevice currentDevice] identifierForVendor] UUIDString];
    res.appKey = APPKEY;
    
    //序列化
    NSData *data = [res data];
    
    if (self.udpSocket == nil) {
        self.udpSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
        
        NSError * error = nil;
        [self.udpSocket bindToPort:self.clientProt error:&error];
        if (error) {
//            VCNSLog(@"error:%@",error);
            for (int i = 1; i<8; i++) {
                error = nil;
                [self.udpSocket bindToPort:self.clientProt + i*10 error:&error];
                if (error == nil) {
                    self.clientProt = self.clientProt + i*10;
                    break;
                }
            }
        }
        [self.udpSocket beginReceiving:&error];
    }
    
    [self.udpSocket sendData:data toHost:self.host port:self.prot withTimeout:SOCKET_OUT_TIME tag:0];
    /**打通道超时*/
//    VCNSLog(@"-----打通道下载新的ts-------%@",self);
    
    __VCWeakSelf
    self.isOutTimeTunnel = YES;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(SOCKET_OUT_TIME * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [weakSelf openTunnelFail];
    });
}

/**订阅
 *isCreateData 是否要创建新的data接受数据
 */
-(void)startSubcribeWithIsCreateData:(BOOL)isCreateData{
    if (self.isFree) return;//当前不需要下载了
    
    self.downloadState = 1;//下载状态
    /**订阅*/
    Request *req = [[Request alloc] init];
    Request_Subcribe *subcribe = [[Request_Subcribe alloc] init];
    req.subcribe = subcribe;
    
    subcribe.tunnelId = self.responseTunnel.tunnelId;
    subcribe.resouceId = [self.dict_file objectForKey:@"fileId"];
    subcribe.subId = self.subId;
    
    NSUInteger dataLength;
    if (self.isAuxiliaryDownload) {//辅助下载
        NSUInteger size = (int)self.endPoint - (int)self.startPoint + 1;
        subcribe.end = (int32_t)self.endPoint;
        subcribe.start = (int32_t)self.startPoint;
        self.totalPackNum = (int)(subcribe.end - subcribe.start);
        subcribe.curr = subcribe.start;
        dataLength = size*1400;
    }else{
        NSUInteger size = [[self.dict_file objectForKey:@"fileSize"] unsignedIntegerValue];
        subcribe.end = (int32_t)(size / PAGE_SIZE);
        dataLength = size;
        if (size % PAGE_SIZE == 0) {
            subcribe.end--;
        }
        subcribe.start = 0;
        self.totalPackNum = subcribe.end;
        
    }
    
    if (isCreateData) {
        self.dataModel.data = [NSMutableData dataWithLength:dataLength];
    }
//    [self createBitmapWith:self.totalPackNum];/**初始化bitmap*/
//    [self createAcceptBitmapWith:self.totalPackNum];//添加完成标记
    subcribe.bitmap = self.Bitmap;
    //序列化
    NSData *requestData = [req data];
    
    if (self.udpSocketDownload) {//存在就订阅
        
        [self.udpSocketDownload sendData:requestData toHost:self.host port:self.responseTunnel.tunnelPort withTimeout:SOCKET_OUT_TIME tag:0];
        
    }else{//不存在就创建
        self.udpSocketDownload = [[GCDAsyncUdpSocket alloc]initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
        
        NSError * errortwo = nil;
        [self.udpSocketDownload bindToPort:self.clientTSProt error:&errortwo];
        
        if (errortwo) {
//            VCNSLog(@"error:%@ ",errortwo);
            for (int i = 1; i<11; i++) {
                errortwo = nil;
                [self.udpSocketDownload bindToPort:self.clientTSProt + i*10 error:&errortwo];
                if (errortwo == nil) {
                    self.clientTSProt = self.clientTSProt + i*10;
                    break;
                }
            }
        }
        
        NSError * errorThree = nil;
        [self.udpSocketDownload beginReceiving:&errorThree];
        [self.udpSocketDownload sendData:requestData toHost:self.host port:self.responseTunnel.tunnelPort withTimeout:SOCKET_OUT_TIME tag:0];
    }
    self.pageMaxIndex = (int)self.startPoint;//重置,重新下载
    /**订阅超时*/
//    VCNSLog(@"-----下载新的ts-------%@",self);
    __VCWeakSelf
    self.isOutTimeSubcribe = YES;
    
    if (!self.isDelaySubcribe) {//当前没有延时
        self.isDelaySubcribe = YES;//当前的有一个延时
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(SOCKET_OUT_TIME * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [weakSelf subcribeFail];
        });
    }
}


/**订阅不成功*/
-(void)subcribeFail{
    self.isDelaySubcribe = NO;
    if (self.isOutTimeSubcribe) {
        VCNSLog(@"来了订阅请求超时 第几次%i  %@ = %@",self.subcribeFailNum,self,[self.dict_file objectForKey:@"fileId"]);
        self.subcribeFailNum++;
        if (self.subcribeFailNum >= 10) {
            if (!self.isNewTunnel) {
                [self openTunnel];
                self.isNewTunnel = YES;
                self.subcribeFailNum = 0;
                [self.udpSocket close];
                [self.udpSocketDownload close];
                self.udpSocket = nil;
                self.udpSocketDownload = nil;
            }
            
        }else{
            [self startSubcribeWithIsCreateData:NO];
        }
    }
}

/**开通道不成功*/
-(void)openTunnelFail{
    if (self.isOutTimeTunnel) {
//        VCNSLog(@"来了通道请求超时 num = %i",self.tunnelFailNum);
        self.tunnelFailNum++;
        if (self.tunnelFailNum >= 10) {//请求新的域名
            [self.udpSocket close];
            [self.udpSocketDownload close];
            self.udpSocket = nil;
            self.udpSocketDownload = nil;
            self.tunnelFailNum = 0;
            [[NSNotificationCenter defaultCenter] postNotificationName:VCDownloadTunnelOpenFailNotification object:self userInfo:@{VC_TS:self}];
        }else{
            [self openTunnel];
        }
    }
}

#pragma mark - GCDAsyncUdpSocketDelegate

- (void)udpSocket:(GCDAsyncUdpSocket *)sock didSendDataWithTag:(long)tag
{
//    VCNSLog(@"发送信息成功");
}

- (void)udpSocket:(GCDAsyncUdpSocket *)sock didNotSendDataWithTag:(long)tag dueToError:(NSError *)error
{
    VCNSLog(@"发送信息失败");
}

- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)dataone fromAddress:(NSData *)address withFilterContext:(id)filterContext
{
    
    if (sock == self.udpSocket) {
        //反序列化
        NSError *error;
        ResponseTunnel *response = [[ResponseTunnel alloc] initWithData:dataone error:&error];
        
        VCNSLog(@"%@ %@",self,response.description);
        
        self.responseTunnel = response;
        self.isNewTunnel = NO;//可以起来,继续可以做超时操作
        /**订阅*/
        [self startSubcribeWithIsCreateData:YES];
        
        //[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(openTunnelFail) object:nil];//取消请求超时事件
        self.isOutTimeTunnel = NO;
    }else{
        //反序列化
        NSError *error;
        Response *resdata = [[Response alloc] initWithData:dataone error:&error];
        self.downloadState = 2;//下载状态
        self.currentRate += [resdata.data_p.payload length];//记录但是速率
        self.downloadTotal += [resdata.data_p.payload length];//总下载量
        self.LastTimestamp = resdata.data_p.timestamp;//记录时间戳
        self.tSize += [resdata.data_p.payload length];//记录流量
        if ([self.delegate respondsToSelector:@selector(download:completeIndex:)]) {//调试界面
            [self.delegate download:self completeIndex:resdata.data_p.index];
        }
        if (self.subId != resdata.data_p.subId || self.isFree) {//不是当前的ts 或者当前下载器没有任务
            return;
        }
        
        
        
//        [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(subcribeFail) object:nil];//取消请求超时事件
        self.isOutTimeSubcribe = NO;
        if (![self bitMapAdjustWithAcceptIndex:resdata.data_p.index]) {//如果存在就不添加到数组里面
            self.pageMaxIndex = resdata.data_p.index > self.pageMaxIndex ?resdata.data_p.index:self.pageMaxIndex;
            [self appendTsDataWith:resdata];
            if ([self.delegate respondsToSelector:@selector(download:bitmap:)]) {//调试界面
                [self.delegate download:self bitmap:self.Bitmap];
            }

            if ([self.acceptBitmap isEqual:self.Bitmap]) {
                [self saveDataLocal];//保存ts
            }
        }
        
    }
}

/**调整batMap的位 存在过就返回yes 不存在就no
 *AcceptIndex : 最新接受的的包
 */
-(BOOL)bitMapAdjustWithAcceptIndex:(int)AcceptIndex{
    AcceptIndex = AcceptIndex - (int32_t)self.startPoint;
    if (AcceptIndex > self.totalPackNum) {//丢弃,这个是给辅助下载
        return YES;
    }
    int loca = AcceptIndex/8;
    
    
    unsigned char orAndNum = 1 << AcceptIndex%8;

    NSRange range = NSMakeRange(loca, 1);
    
    Byte b1;
    [self.Bitmap getBytes:&b1 range:range];//获取要更改位置的byte
    
    //判断是否重复进来
    Byte b2 = b1;
    b2 = b2 & orAndNum;
    unsigned char char2 = (unsigned char)b2;
    if (char2 > 0) {//重复接收到
//        VCNSLog(@"第 %i 重复进来",AcceptIndex);
        return YES;
    }
    
    orAndNum = orAndNum ^ 0xff;
    b1 = ~(b1 ^ orAndNum);//进行同或
    Byte bytess[] = {b1};
    [self.Bitmap replaceBytesInRange:range withBytes:bytess];//重新替换
    
    return NO;
}

/**初始化校验acceptBitmap*/
-(void)createAcceptBitmapWith:(int)num{
    int max = num/8;
    max++;
    int remainder = num%8;
    
    Byte byte[max];
    for (int i = 0; i<max; i++) {
        if (i == max - 1) {//最后那个位置特殊处理
             byte[i] = (Byte)(0xff >> (8-(remainder+1)));
        }else{
            byte[i]= (Byte)(0xff);
        }
    }
    //右移
    self.acceptBitmap = [NSMutableData dataWithBytes:byte length:sizeof(byte)];
    
}

/**初始化bitmap*/
-(void)createBitmapWith:(int)num{
    int max = num/8;
    max++;
    
    Byte byte[max];
    for (int i = 0; i<max; i++) {
        byte[i]= 0 & 0xff;
    }
    //右移
    self.Bitmap = [NSMutableData dataWithBytes:byte length:sizeof(byte)];
    
}

/**拼接之前接受的数据*/
-(void)appendTsDataWith:(Response *)response{
    int index = response.data_p.index - (int32_t)self.startPoint;
    [self.dataModel.data replaceBytesInRange:NSMakeRange(index * PAGE_SIZE, response.data_p.payload.length) withBytes:response.data_p.payload.bytes];
}
/**保存在本地*/
-(void)saveDataLocal{
    if (!self.isFree) {//确认不是暂停之后的ts
        self.isFree = YES;
        if (self.isAuxiliaryDownload) {//辅助下载
            
            if ([self.delegate respondsToSelector:@selector(download:auxiliaryCompleteWithDataModel:)]) {
                [self.delegate download:self auxiliaryCompleteWithDataModel:self.dataModel];
            }
            
        }else{
            
            if ([self.delegate respondsToSelector:@selector(download:completeWithDataModel:)]) {
                [self.delegate download:self completeWithDataModel:self.dataModel];
            }
            
        }
    }
}

@end
